GtkCellArea *area);
static GtkWidget *gtk_tree_menu_get_path_item (GtkTreeMenu *menu,
GtkTreePath *path);
+static gboolean gtk_tree_menu_path_in_menu (GtkTreeMenu *menu,
+ GtkTreePath *path,
+ gboolean *header_item);
static void row_inserted_cb (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
GtkTreePath *path,
GtkTreeIter *iter,
GtkTreeMenu *menu);
-
static void context_size_changed_cb (GtkCellAreaContext *context,
GParamSpec *pspec,
GtkWidget *menu);
+static void area_apply_attributes_cb (GtkCellArea *area,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gboolean is_expander,
+ gboolean is_expanded,
+ GtkTreeMenu *menu);
static void item_activated_cb (GtkMenuItem *item,
GtkTreeMenu *menu);
static void submenu_activated_cb (GtkTreeMenu *submenu,
/* Signals */
gulong size_changed_id;
+ gulong apply_attributes_id;
gulong row_inserted_id;
gulong row_deleted_id;
gulong row_reordered_id;
object_class->set_property = gtk_tree_menu_set_property;
object_class->get_property = gtk_tree_menu_get_property;
- widget_class->get_preferred_width = gtk_tree_menu_get_preferred_width;
- widget_class->get_preferred_height = gtk_tree_menu_get_preferred_height;
+ widget_class->get_preferred_width = gtk_tree_menu_get_preferred_width;
+ widget_class->get_preferred_height = gtk_tree_menu_get_preferred_height;
tree_menu_signals[SIGNAL_MENU_ACTIVATE] =
g_signal_new (I_("menu-activate"),
}
priv->context = gtk_cell_area_create_context (priv->area);
+
priv->size_changed_id =
g_signal_connect (priv->context, "notify",
G_CALLBACK (context_size_changed_cb), menu);
-
return object;
}
return item;
}
-static void
-row_inserted_cb (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- GtkTreeMenu *menu)
+static gboolean
+gtk_tree_menu_path_in_menu (GtkTreeMenu *menu,
+ GtkTreePath *path,
+ gboolean *header_item)
{
GtkTreeMenuPrivate *priv = menu->priv;
- GtkTreePath *parent_path;
- gboolean this_menu = FALSE;
- gint *indices, index, depth;
-
- parent_path = gtk_tree_path_copy (path);
+ GtkTreePath *parent_path = gtk_tree_path_copy (path);
+ gboolean in_menu = FALSE;
+ gboolean is_header = FALSE;
- /* Check if the menu and the added iter are in root of the model */
- if (gtk_tree_path_get_depth (parent_path) <= 1)
+ /* Check if the is in root of the model */
+ if (gtk_tree_path_get_depth (parent_path) == 1)
{
if (!priv->root)
- this_menu = TRUE;
+ in_menu = TRUE;
}
- /* If we are a submenu, compare the path */
- else if (priv->root)
+ /* If we are a submenu, compare the parent path */
+ else if (priv->root && gtk_tree_path_up (parent_path))
{
GtkTreePath *root_path =
gtk_tree_row_reference_get_path (priv->root);
if (gtk_tree_path_compare (root_path, parent_path) == 0)
- this_menu = TRUE;
+ in_menu = TRUE;
+
+ if (!in_menu && priv->menu_with_header &&
+ gtk_tree_path_compare (root_path, path) == 0)
+ {
+ in_menu = TRUE;
+ is_header = TRUE;
+ }
gtk_tree_path_free (root_path);
}
gtk_tree_path_free (parent_path);
+ if (header_item)
+ *header_item = is_header;
+
+ return in_menu;
+}
+
+static void
+row_inserted_cb (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ GtkTreeMenu *menu)
+{
+ GtkTreeMenuPrivate *priv = menu->priv;
+ gint *indices, index, depth;
+
/* If the iter should be in this menu then go ahead and insert it */
- if (this_menu)
+ if (gtk_tree_menu_path_in_menu (menu, path, NULL))
{
GtkWidget *item;
GtkTreeMenu *menu)
{
GtkTreeMenuPrivate *priv = menu->priv;
- GtkTreePath *root_path;
GtkWidget *item;
+ gboolean header_item;
+ gboolean in_menu;
- /* If it's the root node we leave it to the parent menu to remove us
- * from its menu */
- if (priv->root)
- {
- root_path = gtk_tree_row_reference_get_path (priv->root);
+ in_menu = gtk_tree_menu_path_in_menu (menu, path, &header_item);
- if (gtk_tree_path_compare (root_path, path) == 0)
- {
- gtk_tree_path_free (root_path);
- return;
- }
- }
-
- item = gtk_tree_menu_get_path_item (menu, path);
- if (item)
+ /* If it's the header item we leave it to the parent menu
+ * to remove us from its menu
+ */
+ if (!header_item && in_menu)
{
- if (priv->wrap_width > 0)
- rebuild_menu (menu);
- else
+ item = gtk_tree_menu_get_path_item (menu, path);
+ if (item)
{
- /* Get rid of the deleted item */
- gtk_widget_destroy (item);
-
- /* Resize everything */
- gtk_cell_area_context_flush (menu->priv->context);
+ if (priv->wrap_width > 0)
+ rebuild_menu (menu);
+ else
+ {
+ /* Get rid of the deleted item */
+ gtk_widget_destroy (item);
+
+ /* Resize everything */
+ gtk_cell_area_context_flush (menu->priv->context);
+ }
}
}
}
GtkTreeMenuPrivate *priv = menu->priv;
gboolean this_menu = FALSE;
- if (iter == NULL && priv->root == NULL)
+ if (path == NULL && priv->root == NULL)
this_menu = TRUE;
else if (priv->root)
{
}
else if (!has_header && item)
{
- /* Destroy the header item and the following separator */
+ /* Destroy the header item and then the following separator */
gtk_widget_destroy (item);
gtk_widget_destroy (GTK_MENU_SHELL (menu)->children->data);
gtk_widget_queue_resize (menu);
}
+static gboolean
+area_is_sensitive (GtkCellArea *area)
+{
+ GList *cells, *list;
+ gboolean sensitive = FALSE;
+
+ cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
+
+ for (list = cells; list; list = list->next)
+ {
+ g_object_get (list->data, "sensitive", &sensitive, NULL);
+
+ if (sensitive)
+ break;
+ }
+ g_list_free (cells);
+
+ return sensitive;
+}
+
+static void
+area_apply_attributes_cb (GtkCellArea *area,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gboolean is_expander,
+ gboolean is_expanded,
+ GtkTreeMenu *menu)
+{
+ /* If the menu for this iter has a submenu */
+ GtkTreeMenuPrivate *priv = menu->priv;
+ GtkTreePath *path;
+ GtkWidget *item;
+ gboolean is_header;
+ gboolean sensitive;
+
+ path = gtk_tree_model_get_path (tree_model, iter);
+
+ if (gtk_tree_menu_path_in_menu (menu, path, &is_header))
+ {
+ item = gtk_tree_menu_get_path_item (menu, path);
+
+ /* If there is no submenu, go ahead and update item sensitivity,
+ * items with submenus are always sensitive */
+ if (!gtk_menu_item_get_submenu (GTK_MENU_ITEM (item)))
+ {
+ sensitive = area_is_sensitive (priv->area);
+
+ gtk_widget_set_sensitive (item, sensitive);
+
+ if (is_header)
+ {
+ /* For header items we need to set the sensitivity
+ * of the following separator item
+ */
+ if (GTK_MENU_SHELL (menu)->children &&
+ GTK_MENU_SHELL (menu)->children->next)
+ {
+ GtkWidget *separator =
+ GTK_MENU_SHELL (menu)->children->next->data;
+
+ gtk_widget_set_sensitive (separator, sensitive);
+ }
+ }
+ }
+ }
+
+ gtk_tree_path_free (path);
+}
+
static void
gtk_tree_menu_set_area (GtkTreeMenu *menu,
GtkCellArea *area)
GtkTreeMenuPrivate *priv = menu->priv;
if (priv->area)
- g_object_unref (priv->area);
+ {
+ g_signal_handler_disconnect (priv->area,
+ priv->apply_attributes_id);
+ priv->apply_attributes_id = 0;
+
+ g_object_unref (priv->area);
+ }
priv->area = area;
if (priv->area)
- g_object_ref_sink (priv->area);
+ {
+ g_object_ref_sink (priv->area);
+
+ priv->apply_attributes_id =
+ g_signal_connect (priv->area, "apply-attributes",
+ G_CALLBACK (area_apply_attributes_cb), menu);
+ }
}
static gboolean